package embyparse;

import java.util.ArrayList;

import embyparse.noobparser.Matcher;
import embyparse.noobparser.PatternDefinitions;
import embyparse.noobparser.TokenAnalyzer;
import embyparse.parsetree.ParseNode;
import embyparse.tokenizer.Token;
import embyparse.util.TokenStream;
import emby.err.InternalError;

/**
 * The parser manages the parsing of tokens.
 * <br>
 * Usage:
 * 1. Create a parser object from a token stream.
 * <br>
 * 	ex. Parser p = new Parser(stream)
 * <br>
 * 2. Call p.parse()
 * <br>
 * 3. Retrieve the parsed nodes with getParseStack()
 * <br>
 * 4. (Optional) Run the parse stack through TreeToCode to get AST nodes.
 *
 * In the future, change the process to this.
 * 1. Initialize Parser
 *  - Parser p = new Parser();
 * 2. Call parse on the desired stream, which returns a stack
 *  - ArrayList stack = p.parse(stream)
 * 3. Run the stack through TreeToCode to get AST nodes.
 * @author Justin
 *
 */
public class Parser {

	TokenStream stream;
	ArrayList<ParseNode> parsestack;
	ParseNode lookahead;
	Matcher m;

	public Parser(TokenStream s){
		PatternDefinitions.load();

		stream = s;
		m = new Matcher(PatternDefinitions.MATCHING_PATTERNS);
		parsestack = new ArrayList<ParseNode>();
	}

	/**
	 * Generates a parse tree from the stream given
	 * <br>
	 *
	 */
	public void parse(){
		try{
		//System.out.println("patterns loaded: "+m.patterns.size());
		while(stream.hasNext()){ //each iteration of loop parses one line of code (defined as until it hits a semicolon OR /n)
			//read until you hit an EOL
			ArrayList<Token> tokens = new ArrayList<Token>();
			Token token = stream.next();
			tokens.add(token);
			while(stream.hasNext()){
				token = stream.next();
				tokens.add(token);
			}

			//pop tokens in normal order
			lookahead = TokenAnalyzer.analyzeToken(tokens.get(0));
			for(int i = 1; i<tokens.size(); i++){
				parsestack.add(lookahead);
				lookahead = TokenAnalyzer.analyzeToken(tokens.get(i));
				parsestack = m.match(parsestack, lookahead);
			}

			parsestack.add(lookahead);
			//-------------------------------
			parsestack = m.match(parsestack, null);

			if(parsestack.get(parsestack.size()-1).tag.toString().equals("Pattern:;")){
				parsestack.remove(parsestack.size()-1);
			}else{
				//new InternalError("Stack did not end in EOL");
			}
		}
		}finally{
			stream.close();
		}
	}

	/**
	 * Call this AFTER calling parse().
	 * <br>
	 * Returns the stack of parsed nodes.
	 * @return the parsed stack of nodes.
	 */
	public ArrayList<ParseNode> getParseStack(){
		return parsestack;
	}
}
